import { capitalize } from "../utils";
import { ElementTypes, NodeTypes } from "./ast"

export function generate(ast) {
    console.log(ast);
    const returns = traverseNode(ast)
    console.log('returns');
    console.log(returns);
    // 组件需要new Function作为render函数，没有h...这些函数，所以需要把这些函数也带上
    const code = `
    with(ctx){
        const {h,Text,Fragment,renderList,resolveComponent}=MiniVue
        return ${returns}
    }
    `
    return code
}

function traverseNode(node, parent) {
    switch (node.type) {
        case NodeTypes.ROOT:
            if (node.children.length === 1) {
                return traverseNode(node.children[0], node)
            }
            const result = traverseChildren(node)
            return result
        case NodeTypes.ELEMENT:
            return resolveElementASTNode(node, parent)
            break;
        case NodeTypes.INTERPOLATION:
            return createTextVNode(node.content)

            break;
        case NodeTypes.TEXT:
            return createTextVNode(node)
    }
}

function createTextVNode(node) {
    const child = createText(node)
    return `h(Text,null,${child})`
}


function createText({ isStatic = true, content = '' } = {}) {
    return isStatic ? JSON.stringify(content) : content
}

// 专门处理特殊指令
function resolveElementASTNode(node, parent) {
    // 处理v-if v-else
    // <h1 v-if="ok"></h1>
    // <h2 v-else></h2>
    // <h3></h3>
    // 以上编译成这样
    // [ok ? h('h1') : h('h2'), h('h3')]


    // <div v-if="ok"></div>
    // [ok?h('div'):h(Text,null,'')]
    const ifNode = pluck(node.directives, 'if') || pluck(node.directives, 'else-if')
    if (ifNode) {
        // if语句有三部分condition,consequent,alternate
        // condition:是判断条件 例子中的ok
        // consequent:是true条件的渲染函数h('div') 去掉v-if的部分
        // alternate:是ok为false的渲染函数h(Text,null,'')

        let consequent = resolveElementASTNode(node, parent)
        let alternate

        const { children } = parent
        // 找到v-if的兄弟节点v-else
        let i = children.findIndex(child => child === node) + 1
        // i索引的节点可能是个空格，所以要接着往下找到不是空格的v-else节点
        for (; i < children.length; i++) {
            const sibling = children[i]
            if (sibling.type === NodeTypes.TEXT && !sibling.content.trim()) {
                children.splice(i, 1)
                i--
                continue
            }
            // 跳出空格文本节点，找到v-else节点
            if (sibling.type === NodeTypes.ELEMENT) {
                if (pluck(sibling.directives, 'else') || pluck(sibling.directives, 'else-if', false)) {
                    // 是else节点
                    alternate = resolveElementASTNode(sibling, parent)
                    // 渲染之后要把这个节点给删掉，否则会渲染两次
                    children.splice(i, 1)
                }
            }
            break
        }
        const { exp } = ifNode
        // let condition = 
        return `${exp.content}?${consequent}:${alternate || createTextVNode()}`
    }

    // 在这把v-for的删掉
    const forNode = pluck(node.directives, 'for')
    // 存在v-for的指令
    if (forNode) {
        const { exp } = forNode
        // (item,index) in items
        // 拆分成两部分内容
        const [args, source] = exp.content.split(/\sin\s|\sof\s/)
        return `h(Fragment,null,renderList(${source.trim()},${args.trim()}=>${resolveElementASTNode(node, parent)}))`
    }
    return createElementVNode(node)
}

function createElementVNode(node) {
    const { children, tagType } = node
    // nodeType判断是普通元素还是组件

    const tag = tagType === ElementTypes.ELEMENT ? `"${node.tag}"` : `resolveComponent("${node.tag}")`

    // 处理v-model
    const vModel = pluck(node.directives, 'model')
    if (vModel) {
        node.directives.push(
            {
                type: NodeTypes.DIRECTIVE,
                name: 'bind',
                exp: vModel.exp,
                arg: {
                    type: NodeTypes.SIMPLE_EXPRESSION,
                    content: 'value',
                    isStatic: true,
                } // 表达式节点
            },
            {
                type: NodeTypes.DIRECTIVE,
                name: 'on',
                exp: {
                    type: NodeTypes.SIMPLE_EXPRESSION,
                    content: `($event)=>${vModel.exp.content}=$event.target.value`,
                    isStatic: false,
                }, // 表达式节点
                arg: {
                    type: NodeTypes.SIMPLE_EXPRESSION,
                    content: 'input',
                    isStatic: true,
                } // 表达式节点
            }
        )
    }

    const propArr = createPropArr(node)
    const propStr = propArr.length ? `{${propArr.join(', ')}}` : 'null'
    if (!children.length) {
        if (propStr === 'null') {
            return `h(${tag})`
        }
        return `h(${tag},${propStr})`

    }

    let childrenStr = traverseChildren(node)
    return `h(${tag},${propStr},${childrenStr})`
}

// 实现属性的解析
function createPropArr(node) {
    const { props, directives } = node
    return [
        ...props.map(prop => `${prop.name}:${createText(prop.value)}`),
        ...directives.map((dir) => {
            switch (dir.name) {
                case 'bind':
                    return `${dir.arg.content}:${createText(dir.exp)}`
                case 'on':
                    const eventName = `on${capitalize(dir.arg.content)}`
                    let exp = dir.exp.content
                    // 使用直接调用的形式@click=test($event)
                    // 通过判断他是否以括号结尾,并且不包含"=>"
                    if (/\([^)]*?\)$/.test(exp) && !exp.includes('=>')) {
                        exp = `$event => (${exp})`
                    }
                    return `${eventName}:${exp}`
                    break
                case 'html':
                    return `innerHTML:${createText(dir.exp)}`
                default:
                    return `${dir.name}:${createText(dir.exp)}`
            }
        })
    ]
}

function traverseChildren(node) {
    const { children } = node
    if (children.length === 1) {
        const child = children[0]
        if (child.type === NodeTypes.TEXT) {
            // 纯文本节点
            return createText(child)
        }
        if (child.type === NodeTypes.INTERPOLATION) {
            // 插值节点
            return createText(child.content)
        }
    }
    // 多子节点的情况
    const results = []
    for (let i = 0; i < children.length; i++) {
        const child = children[i]
        const result = traverseNode(child, node)
        results.push(result)
    }
    return `[${results.join(', ')}]`
}

// 判断指令是否存在
function pluck(directives, name, remove = true) {
    // 找到该指令
    const index = directives.findIndex(dir => dir.name === name)
    const dir = directives[index]
    if (index > -1 && remove) {
        // 把指令从directive中移除
        directives.splice(index, 1)
    }
    return dir
}